﻿#include "OiPCH.hpp"
#include "View/OiPixmap.hpp"

namespace Oi
{
    namespace PLScannerCore
    {
        class DataCropToolImpl : public Impl<DataCropTool>
        {
        public:
            void init();
            void exit();

        public:
            double _pos;
            double _rangeMin;
            double _rangeMax;
        };

        void DataCropToolImpl::init()
        {
            OI_Q(DataCropTool);

            View::Layer* dynamicLayer = NULL;
            auto pixmap = ImageViewer::OiImageViewer()->pixmap()->pixmap();
            auto pointMap = ImageViewer::OiImageViewer()->pointMap();
            auto rangeMap = ImageViewer::OiImageViewer()->rangeMap();
            auto pointMat = ImageViewer::OiImageViewer()->pointRemapMat();

            if (pointMap.isNull() && pointMat.empty() && rangeMap.isNull() && pixmap.isNull())
            {
                q->deleteLater();
                return;
            }
            if (ImageViewer::OiImageViewer())
            {
                dynamicLayer = ImageViewer::OiImageViewer()->dynamicLayer();
            }

            if (dynamicLayer)
            {
                q->setParentItem(dynamicLayer);
            }

            q->setZValue(50);

            _rangeMin = ImageViewer::OiImageViewer()->imageRect().left();
            _rangeMax = ImageViewer::OiImageViewer()->imageRect().right();

            _pos = _rangeMax;
        }

        void DataCropToolImpl::exit()
        {
        }
      

        DataCropTool::DataCropTool()
        {
            OI_I(DataCropTool)->init();
           
        }

        DataCropTool::~DataCropTool()
        {
            OI_E(DataCropTool)->exit();
        }


        void DataCropTool::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
        {
            OI_F(DataCropTool);
            auto rect = ImageViewer::OiImageViewer()->imageRect();

            rect.setLeft(d->_pos);
            auto sp = rect.topLeft();
            auto ep = rect.bottomRight();


            auto transform = painter->transform();
            painter->save();
            painter->setPen(Qt::NoPen);
            painter->translate(sp);
            painter->scale(1.0 / transform.m11(), 1.0 / transform.m22());
            painter->fillRect(0, 0, (ep.x() - sp.x()) * transform.m11(), (ep.y() - sp.y()) * transform.m22(), QBrush(Qt::red, Qt::DiagCrossPattern));
            painter->restore();
        }

        void DataCropTool::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
        {
            OI_F(DataCropTool);
            auto pos = mapToScene(event->pos());

            d->_pos = pos.x();

            if (pos.x() < d->_rangeMin) d->_pos = d->_rangeMin;
            if (pos.x() >= d->_rangeMax) d->_pos = d->_rangeMax;

            invalidate();
        }

        void DataCropTool::mousePressEvent(QGraphicsSceneMouseEvent *event)
        {
            OI_F(DataCropTool);
            if (event->button() == Qt::LeftButton)
            {
                auto pixmap = ImageViewer::OiImageViewer()->pixmap()->pixmap();
                auto pointMap = ImageViewer::OiImageViewer()->pointMap();
                auto rangeMap = ImageViewer::OiImageViewer()->rangeMap();
                auto pointMat = ImageViewer::OiImageViewer()->pointRemapMat();

                if (!pointMap.isNull() && !pointMat.empty())
                {
                    int l = d->_pos - d->_rangeMin;//ImageViewer::OiImageViewer()->mapImageFromRulerPos(QPointF(_tool->upperPos(), 0)).y();
                    auto point1 = Core::PointMap::create(pointMap->cols(), l);
                    point1->resize(l);
                    for (int i = 0; i < l; i++)
                    {
                        auto pz = pointMap->zLine(i);
                        auto px = pointMap->xLine(i);
                        auto py = pointMap->yLine(i);
                        auto pz1 = point1->zLine(i);
                        auto px1 = point1->xLine(i);
                        auto py1 = point1->yLine(i);

                        /*for (int j = 0; j < pointMap->cols(); j++)
                        {
                            pz1[j] = pz[j];
                            px1[j] = px[j];
                            py1[j] = py[j];
                        }*/
                        memcpy(pz1, pz, pointMap->cols() * sizeof(float));
                        memcpy(px1, px, pointMap->cols() * sizeof(float));
                        memcpy(py1, py, pointMap->cols() * sizeof(float));
                    }

                    ImageViewer::OiImageViewer()->display(point1);
                }
                else if (!rangeMap.isNull())
                {
                    int l = d->_pos - d->_rangeMin;
                    auto range1 = Core::RangeMap::create(rangeMap->cols(), l);
                    for (int i = 0; i < l; ++i)
                    {
                        auto ran = rangeMap->profile(i);
                        auto ran1 = range1->newProfile();
                        memcpy(ran1, ran, rangeMap->cols() * sizeof(float));

                    }


                    ImageViewer::OiImageViewer()->display(range1);
                }
                else if (!pixmap.isNull())
                {
                    int l = d->_pos - d->_rangeMin;
                    QImage im = pixmap.copy(0, 0, pixmap.width(), l);
                    ImageViewer::OiImageViewer()->display(im);
                }
                else
                {
                    deleteLater();
                    return;
                }
                
                ImageViewer::OiImageViewer()->zoomFit();

                deleteLater();
            }
            else if (event->button() == Qt::RightButton) {
                ImageViewer::OiImageViewer()->blockContextMenuEvent();
                deleteLater();
                return;
            }
        }

        void DataCropTool::autoCutData()
        {
            cv::Mat_<float> smat;
            cv::Mat_<float> amp;
            cv::Mat_<float> phase;

            int cutFrom;
            int cutTo;

            auto pointMap = ImageViewer::OiImageViewer()->pointMap();
            auto rangeMap = ImageViewer::OiImageViewer()->rangeMap();
            auto pointMat = ImageViewer::OiImageViewer()->pointRemapMat();

            if(!pointMap.isNull() && !pointMat.empty())
            {
                smat = pointMat(cv::Range::all(), cv::Range::all());
                cutFrom = 0;
                cutTo = pointMat.rows;
            }

            else if(!rangeMap.isNull())
            {
                smat = ( *( cv::Mat_<float>* )( rangeMap->matrix() ) ) ( cv::Range::all(), cv::Range::all() );
                cutFrom = 0;
                cutTo = rangeMap->count();
            }

            if(smat.empty())
            {
                return;
            }

            cv::Mat_<float> line;
            Util::reduceAvg(smat, line, 1);


            double minError = 9999999.0;
            int minErrorIndex = -1;

            QList<double> errors;

            for(int i = cutFrom + qMin(100, ( cutTo - cutFrom ) / 10); i < cutTo - qMin(100, ( cutTo - cutFrom ) / 10); i++)
            {
                auto l1 = i - cutFrom;
                auto l2 = cutTo - i;

                double error = 0.0;

                if(l1 <= l2 * 2)
                {
                    for(int j = 0; j < l1; j++)
                    {
                        auto i1 = j + cutFrom;
                        auto i2 = j + cutTo - l1;

                        error += fabs(line(i1, 0) - line(i2, 0));
                    }

                    error /= l1;

                    errors.push_back(error);

                    if(error < minError)
                    {
                        minError = error;
                        minErrorIndex = i;
                    }
                }
                else
                {
                    break;
                }
            }

            if(minErrorIndex > 0)
            {
                cutFrom = minErrorIndex;

                if(!pointMap.isNull() && !pointMat.empty())
                {
                    auto point1 = Core::PointMap::create(pointMap->cols(), cutTo - cutFrom);
                    point1->resize(cutTo - cutFrom);
                    for(int i = cutFrom; i < cutTo; i++)
                    {
                        auto pz = pointMap->zLine(i);
                        auto px = pointMap->xLine(i);
                        auto py = pointMap->yLine(i);

                        auto pz1 = point1->zLine(i - cutFrom);
                        auto px1 = point1->xLine(i - cutFrom);
                        auto py1 = point1->yLine(i - cutFrom);

                        memcpy(pz1, pz, pointMap->cols() * sizeof(float));
                        memcpy(px1, px, pointMap->cols() * sizeof(float));
                        memcpy(py1, py, pointMap->cols() * sizeof(float));
                    }

                    ImageViewer::OiImageViewer()->display(point1);
                }
                else if(!rangeMap.isNull())
                {
                    auto range1 = Core::RangeMap::create(rangeMap->cols(), cutTo - cutFrom);
                    for(int i = cutFrom; i < cutTo; ++i)
                    {
                        auto ran = rangeMap->profile(i);
                        auto ran1 = range1->newProfile();
                        memcpy(ran1, ran, rangeMap->cols() * sizeof(float));

                    }

                    ImageViewer::OiImageViewer()->display(range1);
                }
            }
        }

    }
}